﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Windows.Navigation;
using System.Xml;
using System.Windows.Markup;
using System.IO;
using System.Windows.Xps.Packaging;
using System.Windows.Xps.Serialization;
using System.Security.Cryptography.X509Certificates;
using System.IO.Packaging;
using System.Windows.Xps;
using System.Printing;
using System.ComponentModel;
using System.Data;

namespace NUMIMAX
{
    /// <summary>
    /// Interaction logic for XPS2.xaml
    /// </summary>
    public partial class XPS : Window
    {
       
        const string packageWithPrintTicketName = "DokumentXPS1.xps";
        const string packageName = "DokumentXPS.xps";
        const string image1 = "picture.jpg";
        const string image2 = "image.tif";
        const string font1 = "courier.ttf";
        const string font2 = "arial.ttf";
        const string fontContentType = "application/vnd.ms-package.obfuscated-opentype";

        public XPS()
        {
            InitializeComponent();
            Loaded += new RoutedEventHandler(MainWindow_Loaded);
        }

        void MainWindow_Loaded(object sender, RoutedEventArgs e)
        {
            Run();

            documentViewer1.Document = openFile(packageName).GetFixedDocumentSequence();
            openFile(packageName).Close();
        }

        public XpsDocument openFile(string _path)
        {
            XpsDocument doc = new XpsDocument(_path, FileAccess.Read);
            return doc;
        }

        public void Run()
        {

            if (File.Exists(packageName))
                File.Delete(packageName);

            using (Package package = Package.Open(packageName))
            {
                XpsDocument xpsDocument = new XpsDocument(package);

                AddPackageContent(xpsDocument, false);

                xpsDocument.Close();
            }

            if (File.Exists(packageWithPrintTicketName))
                File.Delete(packageWithPrintTicketName);

            using (Package package2 = Package.Open(packageWithPrintTicketName))
            {
                XpsDocument xpsDocumentWithPrintTicket = new XpsDocument(package2);
                AddPackageContent(xpsDocumentWithPrintTicket, true);
                xpsDocumentWithPrintTicket.Close();
            }

            string msg = "Stworzyłem dwa XPS dokumenty :\n   - " +
           packageName + "\n   - " + packageWithPrintTicketName;
            MessageBox.Show(msg, "Normal Completion");
        }

        private void AddPackageContent(XpsDocument xpsDocument, bool attachPrintTicket)
        {
            try
            {
                PrintTicket printTicket = GetPrintTicketFromPrinter();
                if (printTicket == null)
                    attachPrintTicket = false;
                IXpsFixedDocumentSequenceWriter documentSequenceWriter =
                xpsDocument.AddFixedDocumentSequence();

                IXpsFixedDocumentWriter fixedDocumentWriter =
                    documentSequenceWriter.AddFixedDocument();

                AddDocumentContent(fixedDocumentWriter);

                fixedDocumentWriter.Commit();

                fixedDocumentWriter = documentSequenceWriter.AddFixedDocument();

                AddDocumentContent(fixedDocumentWriter);

                if (attachPrintTicket)
                    fixedDocumentWriter.PrintTicket = printTicket;

                fixedDocumentWriter.Commit();

                if (attachPrintTicket)
                    documentSequenceWriter.PrintTicket = printTicket;

                documentSequenceWriter.Commit();
            }
            catch (XpsPackagingException xpsException)
            {
                throw xpsException;
            }
        }

        private void AddDocumentContent(IXpsFixedDocumentWriter fixedDocumentWriter)
        {
            Dictionary<string, List<XpsResource>> resources;

            try
            {
                IXpsFixedPageWriter fixedPageWriter =
                    fixedDocumentWriter.AddFixedPage();

                resources = AddPageResources(fixedPageWriter);
                WritePageContent(fixedPageWriter.XmlWriter,
                     "Page 1 of " + fixedDocumentWriter.Uri.ToString(), resources);

                fixedPageWriter.Commit();

                fixedPageWriter = fixedDocumentWriter.AddFixedPage();

                resources = AddPageResources(fixedPageWriter);

                WritePageContent(fixedPageWriter.XmlWriter,
                    "Page 2 of " + fixedDocumentWriter.Uri.ToString(), resources);

                fixedPageWriter.Commit();
            }
            catch (XpsPackagingException xpsException)
            {
                throw xpsException;
            }
        }

        private Dictionary<string, List<XpsResource>>
                AddPageResources(IXpsFixedPageWriter fixedPageWriter)
        {
            Dictionary<string, List<XpsResource>> resources =
                new Dictionary<string, List<XpsResource>>();

            List<XpsResource> xpsImages = new List<XpsResource>();
            List<XpsResource> xpsFonts = new List<XpsResource>();

            try
            {
                XpsImage xpsImage;
                XpsFont xpsFont;

                xpsImage = fixedPageWriter.AddImage(XpsImageType.JpegImageType);
                WriteToStream(xpsImage.GetStream(), image1);
                xpsImage.Commit();
                xpsImages.Add(xpsImage);

                xpsFont = fixedPageWriter.AddFont();
                WriteObfuscatedStream(
                    xpsFont.Uri.ToString(), xpsFont.GetStream(), font1);
                xpsFont.Commit();
                xpsFonts.Add(xpsFont);

                xpsImage = fixedPageWriter.AddImage(XpsImageType.TiffImageType);
                WriteToStream(xpsImage.GetStream(), image2);
                xpsImage.Commit();
                xpsImages.Add(xpsImage);

                xpsFont = fixedPageWriter.AddFont(false);
                WriteToStream(xpsFont.GetStream(), font2);
                xpsFont.Commit();
                xpsFonts.Add(xpsFont);

                resources.Add("XpsImage", xpsImages);
                resources.Add("XpsFont", xpsFonts);
                return resources;
            }
            catch (XpsPackagingException xpsException)
            {
                throw xpsException;
            }
        }

        private PrintTicket GetPrintTicketFromPrinter()
        {
            PrintQueue printQueue = null;

            LocalPrintServer localPrintServer = new LocalPrintServer();

            PrintQueueCollection localPrinterCollection =
                localPrintServer.GetPrintQueues();

            System.Collections.IEnumerator localPrinterEnumerator =
                localPrinterCollection.GetEnumerator();

            if (localPrinterEnumerator.MoveNext())
            {
                printQueue = (PrintQueue)localPrinterEnumerator.Current;
            }
            else
            {
                // No printer exist, return null PrintTicket
                return null;
            }

            PrintTicket printTicket = printQueue.DefaultPrintTicket;

            PrintCapabilities printCapabilites = printQueue.GetPrintCapabilities();

            if (printCapabilites.CollationCapability.Contains(Collation.Collated))
            {
                printTicket.Collation = Collation.Collated;
            }

            if (printCapabilites.DuplexingCapability.Contains(
                    Duplexing.TwoSidedLongEdge))
            {
                printTicket.Duplexing = Duplexing.TwoSidedLongEdge;
            }

            if (printCapabilites.StaplingCapability.Contains(Stapling.StapleDualLeft))
            {
                printTicket.Stapling = Stapling.StapleDualLeft;
            }

            return printTicket;
        }
        private void WritePageContent(XmlWriter xmlWriter, string documentUri, Dictionary<string, List<XpsResource>> resources)
        {
            List<XpsResource> xpsImages = resources["XpsImage"];
            List<XpsResource> xpsFonts = resources["XpsFont"];

            xmlWriter.WriteStartElement("FixedPage");
            xmlWriter.WriteAttributeString("Width", "816");
            xmlWriter.WriteAttributeString("Height", "1056");
            xmlWriter.WriteAttributeString("xmlns",
                "http://schemas.microsoft.com/xps/2005/06");
            xmlWriter.WriteAttributeString("xml:lang", "en-US");

            xmlWriter.WriteStartElement("Glyphs");
            xmlWriter.WriteAttributeString("Fill", "#ff000000");
            xmlWriter.WriteAttributeString(
                "FontUri", xpsFonts[0].Uri.ToString());
            xmlWriter.WriteAttributeString("FontRenderingEmSize", "18");
            xmlWriter.WriteAttributeString("OriginX", "120");
            xmlWriter.WriteAttributeString("OriginY", "110");
            xmlWriter.WriteAttributeString("UnicodeString", documentUri);
            xmlWriter.WriteEndElement();

            xmlWriter.WriteStartElement("Glyphs");
            xmlWriter.WriteAttributeString("Fill", "#ff000000");
            xmlWriter.WriteAttributeString(
                "FontUri", xpsFonts[1].Uri.ToString());
            xmlWriter.WriteAttributeString("FontRenderingEmSize", "16");
            xmlWriter.WriteAttributeString("OriginX", "120");
            xmlWriter.WriteAttributeString("OriginY", "130");
            xmlWriter.WriteAttributeString(
                "UnicodeString", "Test String in Arial");
            xmlWriter.WriteEndElement();

            xmlWriter.WriteStartElement("Path");
            xmlWriter.WriteAttributeString(
                "Data", "M 120,187 L 301,187 301,321 120,321 z");
            xmlWriter.WriteStartElement("Path.Fill");
            xmlWriter.WriteStartElement("ImageBrush");
            xmlWriter.WriteAttributeString(
                "ImageSource", xpsImages[0].Uri.ToString());
            xmlWriter.WriteAttributeString(
                "Viewbox", "0,0,181,134");
            xmlWriter.WriteAttributeString("TileMode", "None");
            xmlWriter.WriteAttributeString(
                "ViewboxUnits", "Absolute");
            xmlWriter.WriteAttributeString(
                "ViewportUnits", "Absolute");
            xmlWriter.WriteAttributeString(
                "Viewport", "120,187,181,134");
            xmlWriter.WriteEndElement();
            xmlWriter.WriteEndElement();
            xmlWriter.WriteEndElement();

            xmlWriter.WriteStartElement("Path");
            xmlWriter.WriteAttributeString(
                "Data", "M 120,357 L 324,357 324,510 120,510 z");
            xmlWriter.WriteStartElement("Path.Fill");
            xmlWriter.WriteStartElement("ImageBrush");
            xmlWriter.WriteAttributeString(
                "ImageSource", xpsImages[1].Uri.ToString());
            xmlWriter.WriteAttributeString(
                "Viewbox", "0,0,204,153");
            xmlWriter.WriteAttributeString(
                "TileMode", "None");
            xmlWriter.WriteAttributeString(
                "ViewboxUnits", "Absolute");
            xmlWriter.WriteAttributeString(
                "ViewportUnits", "Absolute");
            xmlWriter.WriteAttributeString(
                "Viewport", "120,357,204,153");
            xmlWriter.WriteEndElement();
            xmlWriter.WriteEndElement();
            xmlWriter.WriteEndElement();
            xmlWriter.WriteEndElement();
        }

        private void WriteToStream(Stream stream, string resource)
        {
            const int bufSize = 0x1000;
            byte[] buf = new byte[bufSize];
            int bytesRead = 0;

            using (FileStream fileStream =
                new FileStream(resource, FileMode.Open, FileAccess.Read))
            {
                while ((bytesRead = fileStream.Read(buf, 0, bufSize)) > 0)
                {
                    stream.Write(buf, 0, bytesRead);
                }
            }
        }

        private void WriteObfuscatedStream(string resourceName, Stream stream, string resource)
        {
            int bufSize = 0x1000;
            int guidByteSize = 16;
            int obfuscatedByte = 32;

            int startPos = resourceName.LastIndexOf('/') + 1;
            int length = resourceName.LastIndexOf('.') - startPos;
            resourceName = resourceName.Substring(startPos, length);

            Guid guid = new Guid(resourceName);

            string guidString = guid.ToString("N");

            byte[] guidBytes = new byte[guidByteSize];
            for (int i = 0; i < guidBytes.Length; i++)
            {
                guidBytes[i] = Convert.ToByte(guidString.Substring(i * 2, 2), 16);
            }

            using (FileStream filestream = new FileStream(resource, FileMode.Open))
            {
                byte[] buf = new byte[obfuscatedByte];
                filestream.Read(buf, 0, obfuscatedByte);

                for (int i = 0; i < obfuscatedByte; i++)
                {
                    int guidBytesPos = guidBytes.Length - (i % guidBytes.Length) - 1;
                    buf[i] ^= guidBytes[guidBytesPos];
                }
                stream.Write(buf, 0, obfuscatedByte);

                buf = new byte[bufSize];

                int bytesRead = 0;
                while ((bytesRead = filestream.Read(buf, 0, bufSize)) > 0)
                {
                    stream.Write(buf, 0, bytesRead);
                }
            }
        }

        public FixedDocument CreateMyWPFControlReport(ListBox usefulData)
        {
            ListBox controlToPrint;
            controlToPrint = new ListBox();
            controlToPrint.DataContext = usefulData;

            FixedDocument fixedDoc = new FixedDocument();
            PageContent pageContent = new PageContent();
            FixedPage fixedPage = new FixedPage();

            fixedPage.Children.Add(controlToPrint);
            ((System.Windows.Markup.IAddChild)pageContent).AddChild(fixedPage);
            fixedDoc.Pages.Add(pageContent);

            //View the document
            //documentViewer1.Document =
            return fixedDoc;
            // SaveCurrentDocument();
        }

        public void SaveCurrentDocument(DocumentViewer documentViewer1)
        {
            Microsoft.Win32.SaveFileDialog dlg = new Microsoft.Win32.SaveFileDialog();
            dlg.FileName = "MyReport";
            dlg.DefaultExt = ".xps";
            dlg.Filter = "XPS Documents (.xps)|*.xps";

            Nullable<bool> result = dlg.ShowDialog();

            if (result == true)
            {
                string filename = dlg.FileName;

                FixedDocument doc = (FixedDocument)documentViewer1.Document;
                XpsDocument xpsd = new XpsDocument(filename, FileAccess.ReadWrite);
                System.Windows.Xps.XpsDocumentWriter xw = XpsDocument.CreateXpsDocumentWriter(xpsd);
                xw.Write(doc);
                xpsd.Close();
            }
        }

    }
}
